<?php

namespace App\Services;

use App\Models\Permission;
use App\Models\User;
use App\Models\Menu;
use Illuminate\Support\Facades\Cache;

class PermissionService
{
    protected $cachePrefix = 'user_permissions:';
    protected $cacheTime = 3600; // 1小时

    /**
     * 检查用户是否有权限
     *
     * @param User $user
     * @param string $permissionCode 权限编码
     * @return bool
     */
    public function hasPermission(User $user, string $permissionCode): bool
    {
        // 管理员拥有所有权限
        if ($user->isAdmin()) {
            return true;
        }

        $userPermissions = $this->getUserPermissions($user);
        
        return in_array($permissionCode, $userPermissions);
    }

    /**
     * 检查用户是否有菜单权限
     *
     * @param User $user
     * @param int|string $menuId 菜单ID或路径
     * @return bool
     */
    public function hasMenuPermission(User $user, $menuId): bool
    {
        // 管理员拥有所有菜单权限
        if ($user->isAdmin()) {
            return true;
        }

        $menuPermissions = $this->getUserMenuPermissions($user);
        
        if (is_numeric($menuId)) {
            return in_array($menuId, $menuPermissions);
        } else {
            // 如果是路径，查找菜单ID
            $menu = Menu::where('path', $menuId)->first();
            return $menu && in_array($menu->id, $menuPermissions);
        }
    }

    /**
     * 检查用户是否有按钮权限
     *
     * @param User $user
     * @param string $resource 资源标识
     * @param string $action 操作类型
     * @return bool
     */
    public function hasButtonPermission(User $user, string $resource, string $action): bool
    {
        // 管理员拥有所有按钮权限
        if ($user->isAdmin()) {
            return true;
        }

        $permissionCode = Permission::generatePermissionCode($resource, $action);
        return $this->hasPermission($user, $permissionCode);
    }

    /**
     * 检查用户是否有数据权限
     *
     * @param User $user
     * @param string $resource 资源标识
     * @param string $action 操作类型
     * @param mixed $dataId 数据ID（可选）
     * @return bool
     */
    public function hasDataPermission(User $user, string $resource, string $action, $dataId = null): bool
    {
        // 管理员拥有所有数据权限
        if ($user->isAdmin()) {
            return true;
        }

        $permissionCode = Permission::generatePermissionCode($resource, $action);
        
        // 基础权限检查
        if (!$this->hasPermission($user, $permissionCode)) {
            return false;
        }

        // 如果有数据ID，可以进行更细粒度的数据权限检查
        // 例如：只能操作自己部门的数据等
        if ($dataId !== null) {
            // 这里可以根据业务需求添加数据权限逻辑
            // 例如：检查数据是否属于用户部门等
        }

        return true;
    }

    /**
     * 获取用户所有权限编码
     *
     * @param User $user
     * @return array
     */
    public function getUserPermissions(User $user): array
    {
        $cacheKey = $this->cachePrefix . $user->id;
        
        return Cache::remember($cacheKey, $this->cacheTime, function () use ($user) {
            $permissions = [];
            
            $roles = $user->roles()->where('status', 1)->get();
            
            foreach ($roles as $role) {
                $rolePermissions = $role->permissions()
                    ->pluck('code')
                    ->toArray();
                
                $permissions = array_merge($permissions, $rolePermissions);
            }
            
            return array_unique($permissions);
        });
    }

    /**
     * 获取用户菜单权限（菜单ID列表）
     *
     * @param User $user
     * @return array
     */
    public function getUserMenuPermissions(User $user): array
    {
        $cacheKey = $this->cachePrefix . 'menus:' . $user->id;
        
        return Cache::remember($cacheKey, $this->cacheTime, function () use ($user) {
            $menuIds = [];
            
            // 从角色菜单关联获取
            $roles = $user->roles()->where('status', 1)->get();
            foreach ($roles as $role) {
                $roleMenus = $role->menus()
                    ->where('status', 1)
                    ->pluck('menus.id')
                    ->toArray();
                
                $menuIds = array_merge($menuIds, $roleMenus);
            }
            
            // 从菜单权限获取
            $menuPermissions = Permission::where('type', Permission::TYPE_MENU)
                ->whereHas('roles', function ($query) use ($user) {
                    $query->whereIn('roles.id', $user->roles()->pluck('roles.id'));
                })
                ->pluck('menu_id')
                ->toArray();
            
            $menuIds = array_merge($menuIds, $menuPermissions);
            
            return array_unique(array_filter($menuIds));
        });
    }

    /**
     * 获取用户按钮权限（按资源分组）
     *
     * @param User $user
     * @return array
     */
    public function getUserButtonPermissions(User $user): array
    {
        $cacheKey = $this->cachePrefix . 'buttons:' . $user->id;
        
        return Cache::remember($cacheKey, $this->cacheTime, function () use ($user) {
            // 管理员拥有所有按钮权限
            if ($user->isAdmin()) {
                // 所有操作类型
                $allActions = [
                    Permission::ACTION_VIEW,
                    Permission::ACTION_CREATE,
                    Permission::ACTION_UPDATE,
                    Permission::ACTION_DELETE,
                    Permission::ACTION_EXPORT,
                    Permission::ACTION_IMPORT,
                    Permission::ACTION_AUDIT,
                    Permission::ACTION_ASSIGN,
                    Permission::ACTION_RESET,
                ];
                
                // 获取系统中所有按钮权限资源（从数据库中）
                $dbResources = Permission::where('type', Permission::TYPE_BUTTON)
                    ->whereNotNull('resource')
                    ->distinct()
                    ->pluck('resource')
                    ->toArray();
                
                // 常见资源列表（确保即使数据库中没有权限记录，admin也能看到这些资源的按钮）
                $commonResources = [
                    'users',
                    'roles',
                    'permissions',
                    'menus',
                    'departments',
                    'login_logs',
                    'operation_logs',
                    'online_users',
                ];
                
                // 合并数据库资源和常见资源，去重
                $allResources = array_unique(array_merge($dbResources, $commonResources));
                
                // 为每个资源分配所有操作类型
                $permissions = [];
                foreach ($allResources as $resource) {
                    $permissions[$resource] = $allActions;
                }
                
                return $permissions;
            }
            
            // 非管理员用户，返回实际分配的权限
            $permissions = [];
            
            $buttonPermissions = Permission::where('type', Permission::TYPE_BUTTON)
                ->whereHas('roles', function ($query) use ($user) {
                    $query->whereIn('roles.id', $user->roles()->where('status', 1)->pluck('roles.id'));
                })
                ->get();
            
            foreach ($buttonPermissions as $permission) {
                if ($permission->resource && $permission->action) {
                    if (!isset($permissions[$permission->resource])) {
                        $permissions[$permission->resource] = [];
                    }
                    $permissions[$permission->resource][] = $permission->action;
                }
            }
            
            return $permissions;
        });
    }

    /**
     * 清除用户权限缓存
     *
     * @param User $user
     * @return void
     */
    public function clearUserPermissionCache(User $user): void
    {
        Cache::forget($this->cachePrefix . $user->id);
        Cache::forget($this->cachePrefix . 'menus:' . $user->id);
        Cache::forget($this->cachePrefix . 'buttons:' . $user->id);
    }

    /**
     * 清除所有用户权限缓存
     *
     * @return void
     */
    public function clearAllPermissionCache(): void
    {
        // 这里可以实现清除所有权限缓存的逻辑
        // 例如：使用Redis的批量删除
    }

    /**
     * 根据权限过滤菜单
     *
     * @param array $menus 菜单列表
     * @param User $user 用户
     * @return array
     */
    public function filterMenusByPermission(array $menus, User $user): array
    {
        // 管理员拥有所有菜单权限，直接返回所有菜单
        if ($user->isAdmin()) {
            return $menus;
        }
        
        $userMenuIds = $this->getUserMenuPermissions($user);
        
        $filteredMenus = [];
        
        foreach ($menus as $menu) {
            // 检查菜单权限
            if (in_array($menu['id'], $userMenuIds)) {
                // 如果有子菜单，递归过滤
                if (isset($menu['children']) && is_array($menu['children'])) {
                    $menu['children'] = $this->filterMenusByPermission($menu['children'], $user);
                }
                
                $filteredMenus[] = $menu;
            }
        }
        
        return $filteredMenus;
    }
}

